package ormpool

import (
	"errors"
	"sync"
)

var (
	UnSupport   = errors.New("unSupport Type")
	ProxyNoInit = errors.New("proxy no init")
)

type Type int16

const (
	// InvalidType 无效数据库类型
	InvalidType Type = iota
	Mysql
	MongoDb
)

type OrmProxyFac interface {
	CreatProxy(tp Type) (OrmProxy, error)
	GetProxy(tp Type) (OrmProxy, error)
	Release(op OrmProxy)
}
type ormProxyFac struct {
	cache sync.Map
	rwm   sync.RWMutex
}

// NewOrmProxyFac 对外操作的入口初始化函数
func newOrmProxyFac() OrmProxyFac {
	return &ormProxyFac{}
}

func (o *ormProxyFac) CreatProxy(tp Type) (OrmProxy, error) {
	if v, ok := o.cache.Load(tp); ok {
		return v.(OrmProxy), nil
	}
	o.rwm.Lock()
	defer o.rwm.Unlock()
	if v, ok := o.cache.Load(tp); ok {
		return v.(OrmProxy), nil
	}
	switch tp {
	case Mysql:
		p := newMysqlOrmProxy()
		o.cache.Store(tp, p)
		return p, nil
	default:
		return nil, UnSupport
	}
}

func (o *ormProxyFac) GetProxy(tp Type) (OrmProxy, error) {
	if v, ok := o.cache.Load(tp); ok {
		return v.(OrmProxy), nil
	}
	return nil, ProxyNoInit
}

func (o *ormProxyFac) Release(op OrmProxy) {
	o.cache.Delete(op.GetType())
}

type OrmProxy interface {
	CreatPool(schema string, option ...Option) (OrmKey, error)
	GetDB(key OrmKey) (DB, bool)
	Release(key OrmKey) error
	GetType() Type
}

func newMysqlOrmProxy() OrmProxy {
	return &gormMysqlProxy{
		OrmFac: newOrmFac(),
	}
}

type gormMysqlProxy struct {
	OrmFac
}

func (g *gormMysqlProxy) CreatPool(schema string, opt ...Option) (OrmKey, error) {
	om, err := g.OrmFac.Init(schema, opt...)
	if err != nil {
		return 0, err
	}
	return om.GetKey(), nil
}

func (g *gormMysqlProxy) GetDB(key OrmKey) (DB, bool) {
	om, exist := g.OrmFac.GetOrm(key)
	if exist {
		return om.GetDB(), true
	}
	return nil, exist
}

func (g *gormMysqlProxy) Release(key OrmKey) error {
	return g.OrmFac.Release(key)
}
func (g *gormMysqlProxy) GetType() Type {
	return Mysql
}
